﻿using System;
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using Unity.Physics;
using UnityEngine;
using Unity.Mathematics;
using UnityEngine.EventSystems;

public class UnitSelectionManager : MonoBehaviour
{


    public static UnitSelectionManager Instance { get; private set; }


    public event EventHandler OnSelectionAreaStart;
    public event EventHandler OnSelectionAreaEnd;
    public event EventHandler OnSelectionEntitiesChanged;


    private Vector2 selectionStartMousePosition;


    private void Awake()
    {
        Instance = this;
    }

    private void Update()
    {
        //如果EventSystem 碰到了一个UI对象那么直接返回不做操作
        if (EventSystem.current.IsPointerOverGameObject())
        {
            OnSelectionAreaEnd?.Invoke(this, EventArgs.Empty);
            return;
        }

        //如果当前选择的建筑标签不为None 不做单位选择操作
        if (BuildingPlacementManager.Instance.GetActiveBuildingTypeSO().IsNone() == false)
        {
            OnSelectionAreaEnd?.Invoke(this, EventArgs.Empty);
            return;
        }

        if (Input.GetMouseButtonDown(0))
        {
            selectionStartMousePosition = Input.mousePosition;

            OnSelectionAreaStart?.Invoke(this, EventArgs.Empty);
        }
        if (Input.GetMouseButtonUp(0))
        {

            Vector2 selectionEndMousePosition = Input.mousePosition;
            Vector3 mouseWorldPosition = MouseWorldPosition.Instance.GetPosition();

            EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

            EntityQuery entityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<Selected>().Build(entityManager);
            NativeArray<Entity> entityArray = entityQuery.ToEntityArray(Allocator.Temp);
            NativeArray<Selected> selectedArray = entityQuery.ToComponentDataArray<Selected>(Allocator.Temp);
            for (int i = 0; i < entityArray.Length; i++)
            {
                entityManager.SetComponentEnabled<Selected>(entityArray[i], false);
                Selected selected = selectedArray[i];
                selected.onDeselected = true;
                entityManager.SetComponentData(entityArray[i], selected);
            }



            Rect selectionAreaRect = GetSelectionAreaRect();
            float selectionAreaSize = selectionAreaRect.width + selectionAreaRect.height;
            float mutipleSelectionSizeMin = 40f;
            bool isMutipleSelection = selectionAreaSize > mutipleSelectionSizeMin;


            if (isMutipleSelection)
            {
                entityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<LocalTransform, Unit>().WithPresent<Selected>().Build(entityManager);

                entityArray = entityQuery.ToEntityArray(Allocator.Temp);
                NativeArray<LocalTransform> localTransformArray = entityQuery.ToComponentDataArray<LocalTransform>(Allocator.Temp);
                for (int i = 0; i < localTransformArray.Length; i++)
                {
                    LocalTransform unitLocalTransform = localTransformArray[i];
                    Vector2 uintScreeenPostion = Camera.main.WorldToScreenPoint(unitLocalTransform.Position);
                    if (selectionAreaRect.Contains(uintScreeenPostion))
                    {
                        entityManager.SetComponentEnabled<Selected>(entityArray[i], true);
                        Selected selected = entityManager.GetComponentData<Selected>(entityArray[i]);
                        selected.onSelected = true;
                        entityManager.SetComponentData(entityArray[i], selected);
                    }
                }
            }
            else
            {
                //entityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<PhysicsWorldSingleton>().Build(entityManager);
                entityQuery = entityManager.CreateEntityQuery(typeof(PhysicsWorldSingleton));
                PhysicsWorldSingleton physicsWorldSingleton = entityQuery.GetSingleton<PhysicsWorldSingleton>();
                CollisionWorld collisionWorld = physicsWorldSingleton.CollisionWorld;
                UnityEngine.Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition);

                RaycastInput raycastInput = new RaycastInput
                {
                    Start = cameraRay.GetPoint(0f),
                    End = cameraRay.GetPoint(999f),
                    Filter = new CollisionFilter
                    {
                        BelongsTo = ~0u,
                        CollidesWith = 1u << GameAssets.UNITS_LAYER | 1u << GameAssets.BUILDINGS_LAYER,
                        GroupIndex = 0
                    }
                };
                if (collisionWorld.CastRay(raycastInput, out Unity.Physics.RaycastHit raycastHit))
                {
                    if ( entityManager.HasComponent<Selected>(raycastHit.Entity))
                    {
                        entityManager.SetComponentEnabled<Selected>(raycastHit.Entity, true);
                        Selected selected = entityManager.GetComponentData<Selected>(raycastHit.Entity);
                        selected.onSelected = true;
                        entityManager.SetComponentData(raycastHit.Entity, selected);
                    }
                }
            }


            OnSelectionAreaEnd?.Invoke(this, EventArgs.Empty);
            OnSelectionEntitiesChanged?.Invoke(this, EventArgs.Empty);
        }

        if (Input.GetMouseButtonDown(1))
        {
            Vector3 mouseWorldPosition = MouseWorldPosition.Instance.GetPosition();

            EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

            #region 目标覆盖
            EntityQuery entityQuery = entityManager.CreateEntityQuery(typeof(PhysicsWorldSingleton));
            PhysicsWorldSingleton physicsWorldSingleton = entityQuery.GetSingleton<PhysicsWorldSingleton>();
            CollisionWorld collisionWorld = physicsWorldSingleton.CollisionWorld;
            UnityEngine.Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition);
            int unitsLayer = LayerMask.NameToLayer("Uints");
            RaycastInput raycastInput = new RaycastInput
            {
                Start = cameraRay.GetPoint(0f),
                End = cameraRay.GetPoint(999f),
                Filter = new CollisionFilter
                {
                    BelongsTo = ~0u,
                    CollidesWith = 1u << GameAssets.UNITS_LAYER| 1u << GameAssets.BUILDINGS_LAYER,
                    GroupIndex = 0
                }
            };
            bool isAttackingSingleTarget = false;
            if (collisionWorld.CastRay(raycastInput, out Unity.Physics.RaycastHit raycastHit))
            {
                if (entityManager.HasComponent<Faction>(raycastHit.Entity))
                {
                    Faction targetFaction = entityManager.GetComponentData<Faction>(raycastHit.Entity);
                    //查找到点击了僵尸单位 那么将目标覆盖属性设置，让所有士兵集火这个僵尸
                    if (targetFaction.factionType == FactionType.Zomble)
                    {
                        isAttackingSingleTarget = true;

                        entityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<Selected>().WithPresent<TargetOverride>().Build(entityManager);

                        NativeArray<Entity> entityArray = entityQuery.ToEntityArray(Allocator.Temp);
                        NativeArray<TargetOverride> targetOverrideArray = entityQuery.ToComponentDataArray<TargetOverride>(Allocator.Temp);
                        for (int i = 0; i < targetOverrideArray.Length; i++)
                        {
                            TargetOverride moveOverride = targetOverrideArray[i];
                            moveOverride.tagertEntity = raycastHit.Entity;
                            targetOverrideArray[i] = moveOverride;
                            entityManager.SetComponentEnabled<MoveOverride>(entityArray[i], false);
                        }
                        entityQuery.CopyFromComponentDataArray(targetOverrideArray);

                        //单个覆盖不需要了 CopyFrom已经覆盖了所有选择的目标实体中的TargetOverride了
                        //entityManager.SetComponentData(raycastHit.Entity,new TargetOverride { 
                        //    tagertEntity = raycastHit.Entity,
                        //});
                    }
                }
            }

            #endregion
    
            if(!isAttackingSingleTarget)
            {
                entityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<Selected>()
                    .WithPresent<MoveOverride, TargetPositionPathQueued,FlowFieldPathRequset,FlowFieldFollower, TargetOverride>().Build(entityManager);

                NativeArray<Entity> entityArray = entityQuery.ToEntityArray(Allocator.Temp);
                NativeArray<MoveOverride> moveOverrideArray = entityQuery.ToComponentDataArray<MoveOverride>(Allocator.Temp);
                NativeArray<TargetOverride> targetOverrideArray = entityQuery.ToComponentDataArray<TargetOverride>(Allocator.Temp);
                NativeArray<TargetPositionPathQueued> targetPositionPathQueuedArray = entityQuery.ToComponentDataArray<TargetPositionPathQueued>(Allocator.Temp);
                NativeArray<float3> movePostionArray = GenerateMovePositionArray(mouseWorldPosition, entityArray.Length);
                for (int i = 0; i < moveOverrideArray.Length; i++)
                {
                    MoveOverride moveOverride = moveOverrideArray[i];
                    moveOverride.targetPostion = movePostionArray[i];
                    moveOverrideArray[i] = moveOverride;
                    entityManager.SetComponentEnabled<MoveOverride>(entityArray[i], true);

                    TargetOverride targetOverride = targetOverrideArray[i];
                    targetOverride.tagertEntity = Entity.Null;
                    targetOverrideArray[i] = targetOverride;

                    //设置目标流位置
                    TargetPositionPathQueued targetPositionPathQueued = targetPositionPathQueuedArray[i];
                    targetPositionPathQueued.targetPostion = movePostionArray[i];
                    targetPositionPathQueuedArray[i] = targetPositionPathQueued;
                    //设置流场目标队列数组+
                    entityManager.SetComponentEnabled<TargetPositionPathQueued>(entityArray[i], true);
                    //防止单位已经在移动了
                    entityManager.SetComponentEnabled<FlowFieldPathRequset>(entityArray[i], false);
                    entityManager.SetComponentEnabled<FlowFieldFollower>(entityArray[i], false);
                }
                entityQuery.CopyFromComponentDataArray(moveOverrideArray);
                entityQuery.CopyFromComponentDataArray(targetOverrideArray);
                entityQuery.CopyFromComponentDataArray(targetPositionPathQueuedArray);
            }

            ///处理兵营的集结位置
            entityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<Selected,BuildingBarracks,LocalTransform>().Build(entityManager);

            //获取所有兵营
            NativeArray<BuildingBarracks> buildingBarracksArray = entityQuery.ToComponentDataArray<BuildingBarracks>(Allocator.Temp);
            //获取兵营对应的坐标信息
            NativeArray<LocalTransform> buildingLocalTransformArray = entityQuery.ToComponentDataArray<LocalTransform>(Allocator.Temp);
            for (int i = 0; i < buildingBarracksArray.Length; i++)
            {
                BuildingBarracks buildingBarracks = buildingBarracksArray[i];
                //设置兵营生成单位的偏移位置
                buildingBarracks.rallyPositionOffset = (float3)mouseWorldPosition - buildingLocalTransformArray[i].Position;
                buildingBarracksArray[i] = buildingBarracks;
            }
            //保存回原数据中
            entityQuery.CopyFromComponentDataArray(buildingBarracksArray);
        }
    }

    public Rect GetSelectionAreaRect()
    {
        Vector2 selectionEndMousePosition = Input.mousePosition;

        Vector2 lowerLeftCorner = new Vector2(
            Mathf.Min(selectionStartMousePosition.x, selectionEndMousePosition.x),
            Mathf.Min(selectionStartMousePosition.y, selectionEndMousePosition.y));

        Vector2 upperRightCorner = new Vector2(
            Mathf.Max(selectionStartMousePosition.x, selectionEndMousePosition.x),
            Mathf.Max(selectionStartMousePosition.y, selectionEndMousePosition.y));

        return new Rect(
            lowerLeftCorner.x,
            lowerLeftCorner.y,
            upperRightCorner.x - lowerLeftCorner.x,
            upperRightCorner.y - lowerLeftCorner.y
        );
    }

    private NativeArray<float3> GenerateMovePositionArray(float3 tagertPostion, int postionCount)
    {
        NativeArray<float3> postionArray = new NativeArray<float3>(postionCount, Allocator.Temp);
        if (postionCount == 0)
        {
            return postionArray;
        }
        postionArray[0] = tagertPostion;
        if (postionCount == 1)
        {
            return postionArray;
        }
        float ringSize = 2.2f;
        int ring = 0;
        int postionIndex = 1;
        while (postionIndex < postionCount)
        {
            int ringPostionCount = 3 + ring * 2;
            for (int i = 0; i < ringPostionCount; i++)
            {
                float angle = i * (math.PI2 / ringPostionCount);
                float3 ringVector = math.rotate(quaternion.RotateY(angle), new float3(ringSize * (ring + 1), 0, 0));
                float3 ringPostion = tagertPostion + ringVector;
                postionArray[postionIndex] = ringPostion;
                postionIndex++;
                if (postionIndex >= postionCount)
                {
                    break;
                }
            }
            ring++;
        }
        return postionArray;
    }

}